package us.versus.them.bitly;

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.text.TextField;

import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;

class App {

	var w : Int;
	var h : Int;
	var bitmap : Bitmap;

	var bitmapData : BitmapData;
	var bitmapData1 : BitmapData;
	var bitmapData2 : BitmapData;

	var sum : Float;
	var mask : Array< Array< Float > >;

	var busy : Bool; // poor man's sentinel

	var constantChaos : Bool;

	public function new() {
		var root = flash.Lib.current;
		this.w = Math.floor( root.stage.stageWidth  );
		this.h = Math.floor( root.stage.stageHeight );

		this.bitmapData1 = new BitmapData( w, h );
		this.bitmapData2 = new BitmapData( w, h );
		this.bitmapData = this.bitmapData1;

		this.bitmap = new Bitmap();
		this.bitmap.bitmapData = bitmapData;
		root.addChild( this.bitmap );

		constantChaos = !true;

		reset();

		flash.Lib.current.addEventListener( Event.ENTER_FRAME, loop );
		flash.Lib.current.stage.addEventListener( KeyboardEvent.KEY_DOWN, keyDown );
		flash.Lib.current.stage.addEventListener( MouseEvent.MOUSE_DOWN, mouseDown );
	}

	public function mouseDown( _ ) {
		reset();
	}

	public function keyDown( e:KeyboardEvent ) {
		switch( e.charCode ) {
			case 114: constantChaos = !constantChaos; //trace( 'chaos=' + constantChaos );
			default: //trace( e.charCode );
		}
	}

	public function reset() {
		if ( busy ) return;
		busy = true;

		this.bitmapData = this.bitmapData1;
		var m = Math;
		for ( y in 0 ... h ) {
			for ( x in 0 ... w ) {
				bitmapData.setPixel( x, y, m.floor( 0xFFFFFF * m.random() ) );
			}
		}

		var leMode = m.floor( m.random() * 3 );

		var r;
		mask = new Array< Array< Float > >();
		sum = 0;
		for ( i in 0 ... 3 ) {
			mask[ i ] = new Array< Float >();
			for ( j in 0 ... 3 ) {
				switch( leMode ) {
					case 1: r = 1 - m.random() * 2;
					case 2: r = -m.random();
					default: r = m.random();
				}
				sum += r;
				mask[ i ].push( r );
			}
		}
		//sum = 1 - m.random() * 2;
		if ( 0 == sum ) sum = 1;

		busy = false;
	}

	public function loop( _ ) {
		if ( !busy ) {
			busy = true;

			var tmp = inactive();
			applyMask( tmp );
			if ( constantChaos ) {
				chaos( tmp );
			}
			flip( tmp );

			busy = false;
		}
	}

	public function inactive() { 
		return (
			if ( this.bitmapData == this.bitmapData1 ) {
				this.bitmapData2;
			} else { 
				this.bitmapData1;
			}
	   );
	}

	public function applyMask( tmp ) {
		for ( y in 0 ... h ) {
			for ( x in 0 ... w ) {
				var value = 0.0;
				for ( i in 0 ... 3 ) {
					for ( j in 0 ... 3 ) {
						value += (
							pixelAt( x + j - 1, y + i - 1, this.bitmapData )
							* 
							mask[ i ][ j ] 
						);
					}
				}
				tmp.setPixel( x, y, Math.floor( value / sum ) );
			}
		}
	}

	public function pixelAt( x,y,bitmapData ) {
		if ( -1 == x ) x = w - 1; else
		if ( w == x ) x = 0;
		if ( -1 == y ) y = h - 1; else
		if ( h == y ) y = 0;
		return bitmapData.getPixel( x, y );
	}

	public function chaos( tmp ) {
		var m = Math;
		// introduce some color on the left and right 
		for ( y in 0 ... h ) {
			tmp.setPixel( 0, y, m.floor( 0xFFFFFF * m.random() ) );
			tmp.setPixel( w - 1, y, m.floor( 0xFFFFFF * m.random() ) );
		}

		// introduce some color on the top and bottom
		for ( x in 0 ... w ) {
			tmp.setPixel( x, 0, m.floor( 0xFFFFFF * m.random() ) );
			tmp.setPixel( x, h - 1, m.floor( 0xFFFFFF * m.random() ) );
		}

	}

	public function flip( tmp ) {
		// make the inactive bitmapData active
		this.bitmapData = tmp;
		this.bitmap.bitmapData = bitmapData;
	}
}
